/*
 * DOWNLOAD.C Version 1.01 (C)1996 HUDSON SOFT
 * MIX 再生サンプルプログラムバイナリダウンロード関連(DOWNLOAD.C)
 */
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <dos.h>
#include <fcntl.h>
#include <time.h>
#include "mixplay.h"

enum {
    iRESET,iBREAK,iRUN,MPEEK,MPOKE,KPEEK,KPOKE,VPEEK,VPOKE,
    APEEK,APOKE,APEEKP,APOKEP,CPEEK,CPOKE,GETPUT,ADDRESS
};

#define IOCTL_MAX 0x4000

static int pio_handle;
static int pio_flag = FALSE;
static char packet[16];

/* PC-FXGAに割り込みをかけます。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_break(void)
{
    packet[0] = iBREAK;
    *(long *)(packet+1) = 0L;
    my_ioctl(pio_handle,3,(void far *)packet,5);
}

/* PC-FXGAをリセットしたあとの待ち合わせをします。
 *
 * 入力
 * int		    sec    待ち合わせ時間（秒）
 *
 * 出力
 * なし
 */
void _sleep(int sec)
{
    time_t tm;
    while(sec-- > 0){
	tm = time(0);
	while( tm == time(0));
    }
}

/* PC-FXGAをリセットします。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_reset(void)
{
    if (pio_flag) {
	packet[0] = iRESET;
	*(long *)(packet+1) = 0L;
	if(my_ioctl(pio_handle,3,(void far *)packet,5)<5) return;
    }
}

/* PC-FXGAの状態を調べます。
 *
 * 入力
 * なし
 *
 * 出力
 * int              0      動作停止中
 *                  0 以外 動作中（数値は動作中のステータス）
 */
int pio_stat(void)
{
    unsigned char buf[1];

    if (my_ioctl(pio_handle,2,(void far *)buf,1) == 0) return(0);
    if (buf[0] != 0) return(buf[0]);
    return(-1);
}

/* PIOインターフェースの初期化を行います。
 *
 * PIOインターフェースが使用できない場合はエラーを表示して終了します。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_init(void)
{
    if (!pio_flag) {
	if (_dos_open("PCFXPIO$",O_RDONLY,&pio_handle) != 0) {
	    error("PCFXPIO.SYSが組み込まれていません");
	}
	pio_flag = TRUE;
	pio_reset();
	_sleep(2);
	pio_break();
	if (pio_stat()) {
	    error("PC-FXGAが動作中です。PC-FXGAへのプログラム転送ができません");
	}
    }
}

/* PC-FXGAにバイナリデータを転送します。
 *
 * 入力
 * unsigned long    adr    PC-FXGAのメモリアドレス
 * long             len    転送する長さ
 * char far	    *buf   転送データ
 *
 * 出力
 * なし
 */
void pio_mpoke(unsigned long adr,int len,char far *buf)
{
    packet[0] = MPOKE;
    *(long *)(packet+1) = (long)len;
    *(unsigned long *)(packet+5) = adr;
    if (my_ioctl(pio_handle,3,(void far *)packet,9)<9) {
	error("PC-FXGAへのプログラム転送に失敗しました");
    }
    if (my_ioctl(pio_handle,3,buf,len)<len) {
	error("PC-FXGAへのプログラム転送に失敗しました");
    }
}

/* PC-FXGAにプログラムをダウンロードします。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_download(void)
{
    int sts,bin_handle;
    long len;
    unsigned int slen,dlen;
    unsigned long adr;
    char far *bp;
    char mesbuf[256];
    if (_dos_open(load_file,O_RDONLY,&bin_handle) != 0) {
	sprintf(mesbuf,"ファイル(%s)が読み込めません",load_file);
	error(mesbuf);
    }
    if ((bp = my_malloc(IOCTL_MAX)) == NULL) {
	_dos_close(bin_handle);
	error("メモリが足りません");
    }
    len = get_file_size(load_file);
    adr = 0x8000L;
    while(len) {
	slen = (len >= (long)IOCTL_MAX) ? IOCTL_MAX:(unsigned int)len;
	sts = _dos_read(bin_handle,bp,slen,&dlen);
	if ((sts != 0) || (slen != dlen)) {
	    _dos_close(bin_handle);
	    my_free(bp);
	    sprintf(mesbuf,"ファイル(%s)が読み込めません",load_file);
	    error(mesbuf);
	}
	pio_mpoke(adr,(long)slen,bp);
	len -= slen;
	adr += slen;
    }
    _dos_close(bin_handle);
    my_free(bp);
}

/* PC-FXGAのプログラムを起動します。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_run(void)
{
    packet[0] = iRUN;
    *(long *)(packet+1) = 0L;
    *(long *)(packet+5) = 0x8000L;
    if (my_ioctl(pio_handle,3,(void far *)packet,9)<9) {
	error("PC-FXGAの起動に失敗しました");
    }
}

/* PIOインターフェースを終了します。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void pio_close(void)
{
    if (pio_flag) {
	_dos_close(pio_handle);
	pio_flag = FALSE;
    }
}

/* PC-FXGAへのプログラムのロードと実行を行います。
 *
 * 入力
 * なし
 *
 * 出力
 * なし
 */
void load_exec(void)
{
    pio_init();
    pio_download();
    pio_run();
}
